#!/usr/bin/env python
# 1. 请求 json 数据
# 2. 提取 json 数据转换为路径
# 3. 将 url 与 json 路径拼接为完整资源链接，进行 url 编码
# 4. 通过进度条显示下载进度
"""
 用于下载 52pojie 资源的脚本
"""

import requests
import logging
import os
import json
import urllib.parse
import sys
from rich.progress import Progress, BarColumn, TimeElapsedColumn, TextColumn, TaskProgressColumn
import time
from fake_useragent import UserAgent
import re

# 重新配置标准输出的编码为 UTF-8
sys.stdout.reconfigure(encoding='utf-8')
sys.stderr.reconfigure(encoding='utf-8')


logging.basicConfig(level=logging.INFO,
                    format='[%(asctime)s %(levelname)s]: %(message)s',
                    datefmt='%Y-%m-%d %H:%M:%S')


def make_request(url, method='GET', params=None, data=None, headers=None, timeout=15, retries=3):
    for i in range(retries):
        try:
            if method == 'GET':
                response = requests.get(url, params=params, headers=headers, timeout=timeout)
            elif method == 'POST':
                response = requests.post(url, data=data, headers=headers, timeout=timeout)
            elif method == 'PUT':
                response = requests.put(url, data=data, headers=headers, timeout=timeout)
            elif method == 'DELETE':
                response = requests.delete(url, headers=headers, timeout=timeout)
            else:
                raise ValueError("不支持的请求方法，请使用 GET、POST、PUT 或 DELETE")
            # 检查响应状态码
            response.raise_for_status()
            return response
        except requests.RequestException as e:
            logging.error(f"请求发生异常: {e}, 重试次数: {i + 1}/{retries}")
        return None

def process_list_response(response):
    if response:
        if response.status_code == 200:
            try:
                # 获取响应文本
                response_text = response.text
                # 先使用 re.sub 删除开头的非 { 字符
                cleaned_text = re.sub(r'^[^{]+', '', response_text)
                # 再使用 re.sub 删除结尾的非 } 字符
                cleaned_text = re.sub(r'[^}]+$', '', cleaned_text)
                # 尝试将清理后的内容解析为 JSON
                data = json.loads(cleaned_text)
                # print('\n', cleaned_text)
                with open("list.json", "w", encoding='utf-8') as f:
                    # 将 Python 对象存储为 JSON 文件
                    json.dump(data, f, ensure_ascii=False, indent=4)
                logging.info("成功提取并保存 JSON 内容。")
                return data  # 返回解析后的 JSON 数据
            except json.JSONDecodeError:
                logging.info("无法将提取的内容转换为 JSON 格式。")
        else:
            logging.info("请求失败，状态码:", response.status_code)
    return None


def download_resource(target_url, directory="E:\\Network Tools", headers=None):
    try:
        # 从 URL 中提取文件名
        parsed_url = urllib.parse.urlparse(target_url)
        encoded_file_name = os.path.basename(parsed_url.path)
        # 对文件名进行 URL 解码
        decoded_file_name = urllib.parse.unquote(encoded_file_name)
        # 构建完整的文件存储路径，包括子目录，使用解码后的文件名
        decoded_path = urllib.parse.unquote(parsed_url.path)
        file_path = os.path.join(directory, *decoded_path.split('/')[1:])
        # 提取目录部分，不使用编码后的路径并进行解码
        dir_path = os.path.join(directory, *[urllib.parse.unquote(part) for part in target_url.split('/')[3:-1]])
        # 检查文件是否已存在
        if os.path.exists(file_path):
            global file_index  # 使用全局变量来记录文件序号
            print(f"[{file_index}] 文件已存在，跳过下载。 {file_path} ")
            file_index += 1
            return
        response = make_request(target_url, method='GET', headers=headers)
        time.sleep(1)
        if response:
            # 确保目录存在，如果不存在则创建
            os.makedirs(dir_path, exist_ok=True)
            with open(file_path, 'wb') as file:
                file.write(response.content)
                size_in_mb = len(response.content) / (1024 * 1024)
                # 打印解码后的 URL 链接
                decoded_url = urllib.parse.unquote(target_url)
                print(f"URL 资源链接: {decoded_url}\t\t文件大小: {size_in_mb:.2f} MB")
        else:
            logging.error(f"请求失败，未获取到响应")
    except requests.RequestException as e:
        logging.error(f"请求时发生异常: {e}")
    except IOError as e:
        logging.error(f"文件写入时发生异常: {e}")
    time.sleep(1)


def extract_paths(json_data):
    def traverse(data, current_path):
        paths = []
        for item in data:
            new_path = current_path + [item["name"]]
            if "children" in item:
                paths.extend(traverse(item["children"], new_path))
            else:
                paths.append("/".join(new_path))
        return paths
    return traverse(json_data["children"], [])


if __name__ == "__main__":
    file_index = 1  # 初始化文件序号为1
    ua = UserAgent()
    request_headers = {
        "cookie": "cavy_locale=zh_CN; PHPSESSID=d9e6d2738d16a1ecaa6d57b9c9849ddd; top_menustatue_NSFOCUSWAF=2,0,0",
        "User-Agent": ua.random
    }
    
    url_list = "https://down.52pojie.cn/list.js"
    data_list = requests.get(url=url_list, headers=request_headers)
    logging.info(f"响应状态{data_list}")
    # 检查 data_list 是否为 None
    if data_list:
        processed_json = process_list_response(data_list)
        if processed_json:
            with open('list.json', 'r', encoding='utf-8') as file:
                json_data = json.load(file)


            url = "https://down.52pojie.cn/"
            paths = extract_paths(json_data)
            logging.info('资源链接处理完成')
            logging.info('资源开始下载，链接数量: %s', len(paths))


            total_tasks = len(paths)
            # 正确设置进度条的列
            with Progress(TextColumn("[bold blue]{task.description}", justify="right"),
                          BarColumn(bar_width=30),
                          TaskProgressColumn(),
                          TimeElapsedColumn()) as progress:
                task = progress.add_task("[blue] resourcesDownloading...", total=total_tasks, visible=True)
                for index, path in enumerate(paths):
                    encoded_path = urllib.parse.quote(path)
                    download_url = url + encoded_path
                    download_resource(download_url, directory="E:\\Network Tools", headers=request_headers)


                    # 更新进度条，将任务进度和状态信息放到进度条后面
                    if index < total_tasks - 1:
                        progress.update(task, description=f"[red]任务进行中 {index + 1}/{total_tasks}", advance=1)
                    else:
                        progress.update(task, description=f"[green]任务已完成 {index + 1}/{total_tasks}", advance=1)
            logging.info("资源下载成功，请查看下载目录E:\\Network Tools")
        else:
            logging.error("处理列表响应时失败")
    else:
        logging.error("请求列表数据失败")
